Skip to content

Conversation

@konsalex
Copy link
Contributor

@konsalex konsalex commented Jan 25, 2026

AI generated with fixes from me 👇

Summary

Fixes issue #233 (isRemoteControlEnabled is not correct with new participants).

This PR ensures that late-joining participants receive the correct remote-control state from the sharer, rather than incorrectly assuming remote control is enabled.

Two-pronged fix:

Core (Rust): The sharer now tracks remote-control state internally and rebroadcasts it when new participants join, ensuring late joiners receive the current state immediately

Client (TypeScript): Default isRemoteControlEnabled is true across all join flows. Ideally it would be false, but it creates a small "glitch" with a label of having remote control disabled in the session which I didn't like.

Changes

Core (room_service.rs)

  1. Added is_sharer flag to track if this instance is the screen-sharing authority
  2. Added remote_control_enabled state to track current remote-control setting
  3. On PublishTrack (share start): mark as sharer and publish initial remote-control state
  4. On RoomEvent::ParticipantConnected: if sharer, rebroadcast current state to ensure late joiner sync
  5. On PublishControllerCursorEnabled: update internal state for future rebroadcasts
  6. On share stop: reset sharer flag and remote-control state

Concerns

Currently we have this code which resides inside SharingScreen.tsx, which I think has a probability of missing/dropping a message from sharer, if it will get created a bit slower.

  useDataChannel("remote_control_enabled", (msg) => {
    const decoder = new TextDecoder();
    const payload: TPRemoteControlEnabled = JSON.parse(decoder.decode(msg.payload));
    if (payload.payload.enabled == false) {
      updateCallTokens({
        isRemoteControlEnabled: false,
      });
.....

This part, as it updates the call state, it should live inside the main app's window, so we avoid any race conditions.

Summary by CodeRabbit

  • Bug Fixes

    • Ensures late joiners receive the correct remote-control setting when joining an active screen-share session.
    • Prevents redundant state updates to avoid unnecessary UI churn.
  • New Features

    • Remote control now defaults to enabled for sessions.
    • Adds clear toasts notifying participants when the sharer enables or disables remote control.

✏️ Tip: You can customize this high-level summary in your review settings.

@konsalex konsalex requested a review from iparaskev as a code owner January 25, 2026 21:14
@netlify
Copy link

netlify bot commented Jan 25, 2026

Deploy Preview for hoppdocs ready!

Name Link
🔨 Latest commit 3d4ed8c
🔍 Latest deploy log https://app.netlify.com/projects/hoppdocs/deploys/697e05a7974a410008e518fb
😎 Deploy Preview https://deploy-preview-236--hoppdocs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

📝 Walkthrough

Walkthrough

Adds a mutex-protected remote_control_enabled: bool to RoomServiceInner (initialized true), updates it on PublishTrack and PublishControllerCursorEnabled, passes the inner Arc into the room event handler, and rebroadcasts the current remote control state to late joiners on ParticipantConnected.

Changes

Cohort / File(s) Summary
Room service: remote control state
core/src/room_service.rs
Introduce remote_control_enabled: Mutex<bool> in RoomServiceInner (init true). Update state on PublishTrack and PublishControllerCursorEnabled. Pass inner into room event task and rebroadcast RemoteControlEnabled to late joiners on ParticipantConnected.
Frontend: remote control UI updates
tauri/src/components/SharingScreen/SharingScreen.tsx
Handle remote-control data-channel payloads by early-returning if value unchanged; update isRemoteControlEnabled on both enable/disable cases and show corresponding toasts. Minor import formatting changes.

Sequence Diagram

sequenceDiagram
    participant RS as RoomService
    participant RH as RoomEventHandler
    participant P as Participant (late-joiner)

    Note over RS: PublishTrack / PublishControllerCursorEnabled updates rc state
    RS->>RS: Set remote_control_enabled (Mutex)
    RS->>RH: (events stream) room events task has access to inner

    P->>RH: ParticipantConnected
    activate RH
    RH->>RS: Read remote_control_enabled (lock)
    RS-->>RH: remote_control_enabled value
    RH->>P: Publish RemoteControlEnabled event
    deactivate RH
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I nudged a bool with careful paws,

I locked and set it without a cause,
When late ones hop in, they hear the tale,
Remote control: enabled or frail.
A tiny hop of shared control — applause! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: isRemoteControlEnabled sync' directly refers to the main objective of the pull request, which is to fix the synchronization of the isRemoteControlEnabled state for late-joining participants.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-isRemoteControlEnabled-

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@iparaskev
Copy link
Contributor

I was cleaning up this and while testing it hit a limitation of this approach. There is a race on processing the event in the controller. I had disabled remote control but when the controller joined the room no toaster or indication was shown. Reloading made the icon on the top right to appear. Maybe we should store this in the livekit room metadata instead?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tauri/src/components/SharingScreen/SharingScreen.tsx (1)

130-156: ⚠️ Potential issue | 🟡 Minor

Guard reads stale closure state and can skip legitimate transitions.

If two messages arrive before a re-render completes, the second state transition may be dropped. The callback closes over the render-time isRemoteControlEnabled value. When updateCallTokens triggers a store update, there's a window where rapid follow-up messages still use the old captured value in the guard check.

Compare against a ref that tracks the latest value instead:

🔧 Suggested fix using a ref for the latest value
   const { updateCallTokens, callTokens } = useStore();
   const isRemoteControlEnabled = callTokens?.isRemoteControlEnabled ?? false;
+  const isRemoteControlEnabledRef = useRef(isRemoteControlEnabled);
+  useEffect(() => {
+    isRemoteControlEnabledRef.current = isRemoteControlEnabled;
+  }, [isRemoteControlEnabled]);

   useDataChannel("remote_control_enabled", (msg) => {
     const decoder = new TextDecoder();
     const payload: TPRemoteControlEnabled = JSON.parse(decoder.decode(msg.payload));
     const newValue = payload.payload.enabled;

     // Skip if value matches current state
-    if (newValue === isRemoteControlEnabled) {
+    if (newValue === isRemoteControlEnabledRef.current) {
       return;
     }

@konsalex
Copy link
Contributor Author

konsalex commented Feb 1, 2026

TODO: Refactor this to use Livekit's Room metadata. Check if metadata are persistent or not (case for our Rooms implementation because ID is the same)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants